{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3141ee55",
   "metadata": {},
   "source": [
    "## import library"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "999a3adb",
   "metadata": {},
   "outputs": [],
   "source": [
    "import re"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5561f7e5",
   "metadata": {},
   "source": [
    "## class Constant\n",
    "- it define the Constant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "57cca334",
   "metadata": {},
   "outputs": [],
   "source": [
    "GAME_PLAYER = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6']\n",
    "CELL_MART = ['x', 'o']\n",
    "TERMINAL_CONDITION = ['WIN', 'DRAW', 'LOSS']\n",
    "PLAYERREWARD = {\"WIN\":100, \"DRAW\":50, \"LOSS\":0} \n",
    "STEPFORWARDTOEMPTY = [[\"?x ?y1 ?x ?y2\", \"?x ?y1\", \"?y1 ?y2\", \"?x ?y2\", \"?x1 ?y1 ?x2 ?y2\", \"?x1 ?y1\", \"?y1 ?y2\", \"?x1 ?x2\", \"?x2 ?y2\", \"?x1 ?y1 ?x2 ?y2\", \"?x1 ?y1\", \"?y1 ?y2\", \"?x2 ?x1\", \"?x2 ?y2\"],\n",
    " [\"?x ?y1 ?x ?y2\", \"?x ?y1\", \"?y2 ?y1\", \"?x ?y2\", \"?x1 ?y1 ?x2 ?y2\", \"?x1 ?y1\", \"?y2 ?y1\", \"?x1 ?x2\", \"?x2 ?y2\", \"?x1 ?y1 ?x2 ?y2\", \"?x1 ?y1\", \"?y2 ?y1\", \"?x2 ?x1\", \"?x2 ?y2\"]]\n",
    "\n",
    "CONNECT4COLUMN = 6\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc2c03f4",
   "metadata": {},
   "source": [
    "## class ReadFile\n",
    "- read the Ludii file and interpret it"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "cdf3248d",
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReadFile:\n",
    "    def __init__(self, filename):\n",
    "        self.GameInfo = self.loadLudii(filename)\n",
    "    \n",
    "    def loadLudii(self, filename):\n",
    "        flagE = True\n",
    "        flagR = True\n",
    "        flagP = True\n",
    "        \n",
    "        info_dict = {}\n",
    "        for var in self.pre_Process(filename):\n",
    "            if not flagE:\n",
    "                info_dict['equipment'] = self.ProcessEquipment(var.strip())\n",
    "                flagE = True\n",
    "\n",
    "            if not flagR:\n",
    "                if var == \"(\":\n",
    "                    count_ru += 1\n",
    "                elif var == \")\":\n",
    "                    count_ru -=1\n",
    "\n",
    "                if count_ru == 0 and len(string_ru) > 0:\n",
    "                    list_ru.append(string_ru.strip() + \")\")\n",
    "                    string_ru = \"\"\n",
    "                elif count_ru < 0:\n",
    "                    info_dict['rules'] = list_ru\n",
    "                    flagR = True\n",
    "                else:\n",
    "                    string_ru += var\n",
    "\n",
    "            if not flagP:\n",
    "                if var == \"}\":\n",
    "                    info_dict[\"players\"] = string_pl\n",
    "                    flagP = True\n",
    "                string_pl += var\n",
    "\n",
    "            if var.strip() == 'rules':\n",
    "                list_ru = []\n",
    "                string_ru = \"\"\n",
    "                flagR = False\n",
    "                count_ru = 0\n",
    "                pass\n",
    "\n",
    "            if var.strip() == 'equipment':\n",
    "                list_eq = []\n",
    "                string_eq = \"\"\n",
    "                count_eq = 0\n",
    "                flagE = False\n",
    "\n",
    "            elif flagE and flagR:\n",
    "                if var == '(' or var == ')':\n",
    "                    continue\n",
    "                elif var[:4] == 'game':\n",
    "                    info_dict[\"name\"] = var.strip()[6:-1]\n",
    "                elif var[:7] == 'players':\n",
    "                    if var[8:] == \"{\":\n",
    "                        string_pl = \"\"\n",
    "                        flagP = False\n",
    "                    else:\n",
    "                        info_dict[\"players\"] = var[8:]\n",
    "        return info_dict\n",
    "    \n",
    "    def pre_Process(self, filename):\n",
    "        ludCon = self.readfile(filename)\n",
    "        list_pre = []\n",
    "        EQU = True\n",
    "        stringV = \"\"\n",
    "        for var in ludCon:\n",
    "            if not EQU:\n",
    "                if var == \"{\":\n",
    "                    if count != 0:\n",
    "                        stringV += var\n",
    "                    count += 1\n",
    "\n",
    "                elif var == \"}\":\n",
    "                    count -= 1\n",
    "                    if count != 0:\n",
    "                        stringV += var\n",
    "\n",
    "                elif count == 0:\n",
    "                    list_pre.append(stringV)\n",
    "                    stringV = \"\"\n",
    "                    EQU = True\n",
    "                else:\n",
    "                    stringV += var\n",
    "            else:\n",
    "                if stringV.strip() == \"equipment\":\n",
    "                    list_pre.append(stringV.strip())\n",
    "                    stringV = \"\"\n",
    "                    count = 0\n",
    "                    EQU = False\n",
    "\n",
    "                elif var == '(' and EQU:\n",
    "                    if stringV != \"\":\n",
    "                        list_pre.append(stringV)\n",
    "                        stringV = \"\"\n",
    "                    list_pre.append('(')\n",
    "\n",
    "                elif var == ')' and EQU:\n",
    "                    list_pre.append(stringV)\n",
    "                    list_pre.append(\")\")\n",
    "                    stringV = \"\"\n",
    "\n",
    "                else:\n",
    "                    stringV += var\n",
    "        return list_pre\n",
    "    \n",
    "    \n",
    "    def ProcessEquipment(self, var_eq):\n",
    "        list_eq = []\n",
    "        string_eq = \"\"\n",
    "        count = 0\n",
    "            \n",
    "        for var in var_eq:\n",
    "            string_eq += var\n",
    "            if var == \"(\":\n",
    "                count += 1\n",
    "            elif var == \")\":\n",
    "                count -= 1\n",
    "            \n",
    "            if count == 0 and string_eq.strip() != \"\":\n",
    "                list_eq.append(string_eq.strip())\n",
    "                string_eq = \"\"\n",
    "        return list_eq\n",
    "        \n",
    "    def readfile(self, fileName):\n",
    "        '''\n",
    "        read the file\n",
    "        :param fileName: the name of file\n",
    "        return the context of file\n",
    "        '''\n",
    "        with open(fileName) as fp:\n",
    "            content = fp.read().split(\"\\n\")\n",
    "            index = 0\n",
    "            for i in range(len(content)):\n",
    "                content[i] = content[i].strip()\n",
    "                if \"//----\" in content[i]:\n",
    "                    index = i\n",
    "                    break\n",
    "            return \" \".join(content[:index])\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2d80b91",
   "metadata": {},
   "source": [
    "## class KeyTranslation\n",
    "- translate the keyword of Ludii"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4936898a",
   "metadata": {},
   "outputs": [],
   "source": [
    "class KeyTranslation:\n",
    "    def __init__(self, ludii):\n",
    "        self.ludii = ludii\n",
    "        self.gdl = self.translate()\n",
    "    \n",
    "    def translate(self):\n",
    "        pass\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92d61ede",
   "metadata": {},
   "source": [
    "### class Game\n",
    "- translate the game name\n",
    "  + Ludii Format: ***game \\<string>***\n",
    "    * game: keyword\n",
    "    * \\<string>: define the name of game, it's string-based\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "9d1bd240",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Game(KeyTranslation):\n",
    "    '''\n",
    "    translate the game name from ludii to GDL\n",
    "    :param gameName: the name of game\n",
    "    return string-based GDL\n",
    "    '''\n",
    "    def translate(self):\n",
    "        context = \";\"*80 + \"\\n\" + f\";;; {self.ludii}\\n\" + \";\"*80 + \"\\n\"\n",
    "        return context\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2cb5de61",
   "metadata": {},
   "source": [
    "### class Players\n",
    "\n",
    "- translate the players\n",
    "  + Ludii Format: ***players \\<int | string>***\n",
    "    * players: keyword\n",
    "    * \\<int | string>: define the players\n",
    "      - if using *int*, it define the size of players\n",
    "      - if using *string*, it define the name of players"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "721a269a",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Players(KeyTranslation):\n",
    "    def translate(self):\n",
    "        '''\n",
    "        translate the players description from ludii to GDL\n",
    "        :param players: a list that including the name of player\n",
    "        return string-based GDL\n",
    "        '''\n",
    "        context = \";\"*80 + \"\\n\" + \";; Roles\\n\" + \";\"*80 + \"\\n\"\n",
    "        \n",
    "        if self.ludii.isdigit():\n",
    "            self.num_pl = int(self.ludii)\n",
    "        else:\n",
    "            self.num_pl = self.StringP2DigitP()\n",
    "        \n",
    "        \n",
    "        for index in range(self.num_pl):\n",
    "            context += f\"(role {GAME_PLAYER[index]})\\n\"\n",
    "        context += \"\\n\"\n",
    "        \n",
    "        context += self.translate_turn()\n",
    "        return context\n",
    "    \n",
    "    def StringP2DigitP(self):\n",
    "        count = 0\n",
    "        for var in self.ludii:\n",
    "            if var == \"(\":\n",
    "                count += 1\n",
    "        return count\n",
    "    \n",
    "    \n",
    "    def translate_turn(self):\n",
    "        \"\"\"\n",
    "        translate the mode\n",
    "        :param players: the list of player\n",
    "        return string-based GDL that including the turn mode\n",
    "        \"\"\"\n",
    "        context = \";\"*80 + \"\\n\" + \";; Game Mode\\n\" + \";\"*80 + \"\\n\"\n",
    "        for i in range(self.num_pl):\n",
    "            context += f\"(<= (next (control {GAME_PLAYER[i]})) (true (control {GAME_PLAYER[(i+1)%self.num_pl]})))\\n\"\n",
    "        context += \"\\n\"\n",
    "        return context"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfb8b17f",
   "metadata": {},
   "source": [
    "### class Equipment\n",
    "- translate equipment of ludii\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "147610ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Equipment(KeyTranslation):\n",
    "    def translate(self):\n",
    "        context = \";\"*80 + \"\\n\" + \";; Initial State\\n\" + \";\"*80 + \"\\n\"\n",
    "        self.flag_init = False\n",
    "        \n",
    "        for var in self.ludii:\n",
    "            if var[1:6] == \"board\":\n",
    "                self.type_board, self.size_board = self.translate_board(var[7:-1])\n",
    "            \n",
    "            elif var[1:6] == \"piece\":\n",
    "                self.flag_init = self.translate_piece(var[7:-1])\n",
    "                \n",
    "            elif var[1:8] == \"regions\":\n",
    "                context += self.translate_init_True(var[9:-1])\n",
    "                self.flag_init = True\n",
    "        \n",
    "        if not self.flag_init:\n",
    "            context += self.translate_init_False()\n",
    "        \n",
    "        else:\n",
    "            context += self.translate_comparison()\n",
    "        \n",
    "        context += f\"(init (control {GAME_PLAYER[0]}))\\n\\n\"\n",
    "        return context\n",
    "            \n",
    "    \n",
    "    \n",
    "    def translate_board(self, ludii_board):\n",
    "        if re.search(\"\\(square ([0-9]*)\\)\", str.lower(ludii_board)):\n",
    "            return \"square\", int(re.search(\"\\(square ([0-9]*)\\)\", str.lower(ludii_board))[1])\n",
    "        \n",
    "        elif re.search(\"\\(rectangle ([0-9]* [0-9]*)\\)\", str.lower(ludii_board)):\n",
    "            return \"rectangle\", int(re.search(\"\\(rectangle ([0-9]* [0-9]*)\\)\", str.lower(ludii_board))[1][-1])\n",
    "        return None, None\n",
    "    \n",
    "    def translate_piece(self, ludii_piece):\n",
    "        if re.search(\"\\\"[Disc|Cross]+\\\" P[0-9]*\", ludii_piece):\n",
    "            return False\n",
    "        return False\n",
    "    \n",
    "    # no limitation of init\n",
    "    def translate_init_False(self):\n",
    "        # translating square type\n",
    "        context = \"\"\n",
    "        if self.type_board == \"square\":\n",
    "            for i in range(1, self.size_board+1):\n",
    "                for j in range(1, self.size_board+1):\n",
    "                    context += f\"(init (cell {i} {j} b))\\n\"\n",
    "        \n",
    "        elif self.type_board == \"rectangle\":\n",
    "            for i in range(1, self.size_board+1):\n",
    "                context += f\"(init (cell {i} 0 dirt))\\n\"\n",
    "                \n",
    "            for i in range(1, self.size_board+1):\n",
    "                for j in range(1, CONNECT4COLUMN+1):\n",
    "                    context += f\"(init (cell {i} {j} b))\\n\"\n",
    "            context += self.translate_comparison()\n",
    "        return context\n",
    "    \n",
    "    \n",
    "    def translate_init_True(self, init_ludii):\n",
    "        context = \"\"\n",
    "        player = re.search(\"(P[0-9]*) \\(sites ([Top|Bottom]+)\\)\", init_ludii)[1]\n",
    "        region = re.search(\"(P[0-9]*) \\(sites ([Top|Bottom]+)\\)\", init_ludii)[2]\n",
    "        if region == \"Top\":\n",
    "            for j in range(1, 3):\n",
    "                for i in range(1, self.size_board+1):\n",
    "                    context += f\"(init (cellholds {i} {j} {player}))\\n\"\n",
    "        elif region == \"Bottom\":\n",
    "            for j in range(2):\n",
    "                for i in range(1, self.size_board+1):\n",
    "                    context += f\"(init (cellholds {i} {self.size_board-j} {player}))\\n\"\n",
    "        return context\n",
    "    \n",
    "    def translate_comparison(self):\n",
    "        context = \"\"\n",
    "        context += \"(index 0) (index 1) (index 2) (index 3) (index 4) (index 5) (index 6) (index 7) (index 8)\\n\" \n",
    "        context += \"(++ 0 1) (++ 1 2)  (++ 2 3)  (++ 3 4)  (++ 4 5)  (++ 5 6)  (++ 6 7)  (++ 7 8)\\n\"\n",
    "        return context"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12c53528",
   "metadata": {},
   "source": [
    "### class Rules\n",
    "- translate the rules of game including(start, play, end)\n",
    "  * Ludii format: ***play \\<moves>***\n",
    "    + play: keyword\n",
    "    + \\<moves>: the legal moves of playing rules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "id": "44578dc5",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Rules(KeyTranslation):\n",
    "    def __init__(self, ludii, num_pl, size_board, type_board):\n",
    "        self.ludii = ludii\n",
    "        self.num_pl = num_pl\n",
    "        self.size_board = size_board\n",
    "        self.type_board = type_board\n",
    "        self.gdl = self.translate()\n",
    "    \n",
    "    \n",
    "    def translate(self):\n",
    "        context = \"\"\n",
    "        for var in self.ludii:\n",
    "            if var[1:5] == \"play\": # should be change as keyword variable\n",
    "                context += self.translate_play(var)\n",
    "            \n",
    "            elif var[1:4] == \"end\":\n",
    "                context += self.translate_end(var)\n",
    "        return context\n",
    "    \n",
    "    \n",
    "    def translate_play(self, keyword_play):\n",
    "        lm = LudiiMove(keyword_play[5:-1], self.num_pl)\n",
    "        return lm.legalMoveGDL + lm.MoveUpdate\n",
    "    \n",
    "    \n",
    "    def translate_end(self, keyword_end):\n",
    "        le = LudiiEnd(keyword_end[5:-1], self.size_board, self.num_pl)\n",
    "        return le.winCondition + le.reward + le.terminal\n",
    "\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9eee887b",
   "metadata": {},
   "source": [
    "#### class LudiiMove\n",
    "- translate ***move*** operator\n",
    "  + add function\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "df6cb1d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "class LudiiMove:\n",
    "    def __init__(self, ludii, num_pl):\n",
    "        self.ludii = ludii\n",
    "        self.num_pl = num_pl\n",
    "        self.legalMoveGDL, self.MoveUpdate = self.translate()\n",
    "    \n",
    "    def translate(self):\n",
    "        if self.ludii[7:10] == \"Add\": # should be change as keyword\n",
    "            return self.translate_Add(self.ludii[11:-1])\n",
    "        elif self.ludii.strip() == \"(forEach Piece)\": # StepForwardToEmpty\n",
    "            return self.translate_StepForwardToEmpty(\"StepForwardToEmpty\") # should be change\n",
    "        return \"Legal Action None\\n\", \"Update none\\n\"\n",
    "    \n",
    "    def translate_Add(self, keyword_add):\n",
    "        context_LegalAction = \";\"*80 + \"\\n\" + \";; Legal Action\\n\" + \";\"*80 + \"\\n\"\n",
    "        context_Update = \";\"*80 + \"\\n\" + \";;  Move & Update\\n\" + \";\"*80 + \"\\n\"\n",
    "        \n",
    "        if keyword_add == \"(to (sites Empty))\":\n",
    "            # translating legal action\n",
    "            context_LegalAction += \"(<= open (true (cell ?m ?n b)))\\n\"\n",
    "            for i in range(self.num_pl):\n",
    "                context_LegalAction += f\"(<= (legal {GAME_PLAYER[(i+1)%self.num_pl]} noop) (true (control {GAME_PLAYER[i]})))\\n\"\n",
    "            context_LegalAction += \"(<= (legal ?w (mark ?x ?y)) (true (cell ?x ?y b)) (true (control ?w)))\\n\\n\"\n",
    "            \n",
    "            # translating move update\n",
    "            for i in range(self.num_pl):\n",
    "                context_Update += f\"(<= (next (cell ?m ?n {CELL_MART[i]})) (does {GAME_PLAYER[i]} (mark ?m ?n)) (true (cell ?m ?n b)))\\n\"\n",
    "\n",
    "            # update mark cell\n",
    "            context_Update += \"(<= (next (cell ?m ?n ?w)) (true (cell ?m ?n ?w)) (distinct ?w b))\\n\"\n",
    "            context_Update += \"(<= (next (cell ?m ?n b)) (does ?w (mark ?j ?k)) (true (cell ?m ?n b)) (or (distinct ?m ?j) (distinct ?n ?k)))\\n\\n\"\n",
    "        \n",
    "        elif \"stack\" in str.lower(keyword_add):\n",
    "            # translating legal action\n",
    "            context_LegalAction += \"(<= open (true (cell ?m ?n b)))\\n\"\n",
    "            for i in range(self.num_pl):\n",
    "                context_LegalAction += f\"(<= (legal {GAME_PLAYER[(i+1)%self.num_pl]} noop) (true (control {GAME_PLAYER[i]})))\\n\"\n",
    "            context_LegalAction += \"(<= (legal ?w (drop ?c)) (true (cell ?c ?y2 b)) (filled ?c ?y1) (++ ?y1 ?y2) (true (control ?w)))\\n\"\n",
    "            \n",
    "            # translating move update\n",
    "            for i in range(self.num_pl):\n",
    "                context_Update += f\"(<= (next (cell ?c ?h2 {CELL_MART[i]})) (does {GAME_PLAYER[i]} (drop ?c)) (true (cell ?c ?h2 b)) (filled ?c ?h1) (++ ?h1 ?h2))\\n\"\n",
    "            context_Update += \"(<= (next (cell ?c ?y2 b)) (true (cell ?c ?y1 b)) (distinct ?y1 6) (++ ?y1 ?y2))\\n\"\n",
    "            context_Update += \"(<= (next (cell ?x ?y ?z)) (true (cell ?x ?y ?z)) (distinct ?z b))\\n\"\n",
    "            context_Update += \"(<= (next (cell ?c2 ?y b)) (does ?w (drop ?c1)) (true (cell ?c2 ?y b)) (distinct ?c1 ?c2))\\n\"\n",
    "            \n",
    "            for i in range(self.num_pl):\n",
    "                context_Update += f\"(<= (filled ?c ?h) (true (cell ?c ?h {CELL_MART[i]})))\\n\"\n",
    "            context_Update += \"(<= (filled ?c ?h) (true (cell ?c ?h dirt)))\\n\"\n",
    "        return context_LegalAction, context_Update\n",
    "    \n",
    "    def translate_StepForwardToEmpty(self, keyword_forEach):\n",
    "        if keyword_forEach == \"StepForwardToEmpty\":\n",
    "            context_LegalAction = \";\"*80 + \"\\n\" + \";; Legal Action\\n\" + \";\"*80 + \"\\n\"\n",
    "            for i in range(self.num_pl):\n",
    "                context_LegalAction += f\"(<= (legal {GAME_PLAYER[(i+1)%self.num_pl]} noop) (true (control {GAME_PLAYER[i]})))\\n\"\n",
    "            \n",
    "            for i in range(self.num_pl):    \n",
    "                context_LegalAction += f\"(<= (legal {GAME_PLAYER[i]} (move {STEPFORWARDTOEMPTY[i][0]})) (true (control {GAME_PLAYER[i]})) (true (cellholds {STEPFORWARDTOEMPTY[i][1]} {GAME_PLAYER[i]})) (++ {STEPFORWARDTOEMPTY[i][2]}) (cellempty {STEPFORWARDTOEMPTY[i][3]}))\\n\"\n",
    "                context_LegalAction += f\"(<= (legal {GAME_PLAYER[i]} (move {STEPFORWARDTOEMPTY[i][4]})) (true (control {GAME_PLAYER[i]})) (true (cellholds {STEPFORWARDTOEMPTY[i][5]} {GAME_PLAYER[i]})) (++ {STEPFORWARDTOEMPTY[i][6]}) (++ {STEPFORWARDTOEMPTY[i][7]}) (not (true (cellholds {STEPFORWARDTOEMPTY[i][8]} {GAME_PLAYER[i]}))))\\n\"\n",
    "                context_LegalAction += f\"(<= (legal {GAME_PLAYER[i]} (move {STEPFORWARDTOEMPTY[i][9]})) (true (control {GAME_PLAYER[i]})) (true (cellholds {STEPFORWARDTOEMPTY[i][10]} {GAME_PLAYER[i]})) (++ {STEPFORWARDTOEMPTY[i][11]}) (++ {STEPFORWARDTOEMPTY[i][12]}) (not (true (cellholds {STEPFORWARDTOEMPTY[i][13]} {GAME_PLAYER[i]}))))\\n\"\n",
    "            context_LegalAction += \"\\n\"\n",
    "            \n",
    "            context_Update = \";\"*80 + \"\\n\" + \";;  Move & Update\\n\" + \";\"*80 + \"\\n\"\n",
    "            \n",
    "            context_Update += \"(<= (next (cellholds ?x2 ?y2 ?player)) (role ?player) (does ?player (move ?x1 ?y1 ?x2 ?y2)))\\n\"\n",
    "            context_Update += \"(<= (next (cellholds ?x3 ?y3 ?state)) (true (cellholds ?x3 ?y3 ?state)) (role ?player) (does ?player (move ?x1 ?y1 ?x2 ?y2)) (distinctcell ?x1 ?y1 ?x3 ?y3) (distinctcell ?x2 ?y2 ?x3 ?y3))\\n\"\n",
    "            context_Update += \"(<= (cell ?x ?y) (index ?x) (index ?y))\\n\"\n",
    "            context_Update += \"(<= (cellempty ?x ?y) (cell ?x ?y) (not (true (cellholds ?x ?y P1))) (not (true (cellholds ?x ?y P2))))\\n\"\n",
    "            context_Update += \"(<= (distinctcell ?x1 ?y1 ?x2 ?y2) (cell ?x1 ?y1) (cell ?x2 ?y2) (distinct ?x1 ?x2))\\n\"\n",
    "            context_Update += \"(<= (distinctcell ?x1 ?y1 ?x2 ?y2) (cell ?x1 ?y1) (cell ?x2 ?y2) (distinct ?y1 ?y2))\\n\\n\"\n",
    "            \n",
    "        return context_LegalAction, context_Update\n",
    "        pass\n",
    "    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a147546e",
   "metadata": {},
   "source": [
    "#### class LudiiEnd\n",
    "- translate ***end*** operator\n",
    "  + ludii format: ***is line \\<int>***"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "id": "d43395d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "class LudiiEnd:\n",
    "    def __init__(self, ludii, size_board, num_pl):\n",
    "        self.ludii = ludii\n",
    "        self.size_board = size_board\n",
    "        self.num_pl = num_pl\n",
    "        self.winCondition, self.reward, self.terminal = self.translate()\n",
    "    \n",
    "    \n",
    "    def translate(self):\n",
    "        if self.ludii[1:3] == \"if\":\n",
    "            return self.translate_if(self.ludii[4:-1])\n",
    "\n",
    "        elif self.ludii[2:10] == \"ReachWin\":\n",
    "            winCondition_GDL, terminal_key = LudiiWinCondition(self.ludii, self.size_board, 0, self.num_pl).translate_reachWin()\n",
    "            reward_GDL = LudiiReward(terminal_key, self.num_pl).translate()\n",
    "            terminal_GDL = LudiiTerminalKey(terminal_key, self.num_pl).translate()\n",
    "            return winCondition_GDL, reward_GDL, terminal_GDL\n",
    "\n",
    "        return \"winCondition None\\n\", \"Reward None\\n\", \"Terminal None\\n\"\n",
    "    \n",
    "    \n",
    "    def translate_if(self, end_if):\n",
    "        list_end = self.getEnds_if(end_if)\n",
    "        winCondition_GDL = \"\"\n",
    "        reward_GDL = \"\"\n",
    "        terminal_GDL = \"\"\n",
    "        terminal_key = \"\"\n",
    "        flag_draw = False\n",
    "        for var in list_end:\n",
    "            if re.search(\"\\(is Line ([1-9]*)\\)$\", var):\n",
    "                winCondition_GDL, terminal_key = LudiiWinCondition(var, self.size_board, re.search(\"\\(is Line ([1-9]*)\\)$\", var)[1], self.num_pl).translate_line()\n",
    "                terminal_GDL = LudiiTerminalKey(terminal_key, self.num_pl).translate()\n",
    "            \n",
    "            elif re.search(\"\\(is Line ([1-9]*) byLevel:True\\)$\", var):\n",
    "                winCondition_GDL, terminal_key = LudiiWinCondition(var, self.size_board, re.search(\"\\(is Line ([1-9]*) byLevel:True\\)$\", var)[1], self.num_pl).translate_line_byLevel()\n",
    "                flag_draw = True\n",
    "                \n",
    "            elif var[1:7] == \"result\":\n",
    "                reward_GDL = LudiiReward(terminal_key, self.num_pl).translate_draw(flag_draw)\n",
    "                terminal_GDL = LudiiTerminalKey(terminal_key, self.num_pl).translate()\n",
    "                \n",
    "        return winCondition_GDL, reward_GDL, terminal_GDL\n",
    "                \n",
    "                \n",
    "    \n",
    "    def getEnds_if(self, end_if):\n",
    "        list_end = []\n",
    "        string_end = \"\"\n",
    "        count = 0\n",
    "        \n",
    "        for var in end_if:\n",
    "            string_end += var\n",
    "            if var == \"(\":\n",
    "                count += 1\n",
    "            \n",
    "            elif var == \")\":\n",
    "                count -= 1\n",
    "            \n",
    "            if count == 0 and string_end != \" \":\n",
    "                list_end.append(string_end.strip())\n",
    "                string_end = \"\"\n",
    "        return list_end\n",
    "\n",
    "\n",
    "    \n",
    "class LudiiWinCondition:\n",
    "    def __init__(self, ludii, size_board, length_line, num_pl):\n",
    "        self.ludii = ludii\n",
    "        self.size_board = size_board\n",
    "        self.length_line = int(length_line)\n",
    "        self.num_pl = num_pl\n",
    "    \n",
    "    def translate_line(self):\n",
    "        context = \";\"*80 + \"\\n\" + \";; Win Condition\\n\" + \";\"*80 + \"\\n\"\n",
    "        if self.size_board == self.length_line:\n",
    "            contextRow = \"(<= (row ?m ?x)\"\n",
    "            contextCol = \"(<= (column ?n ?x)\"\n",
    "            contextDia1 = \"(<= (diagonal ?x)\"\n",
    "            contextDia2 = \"(<= (diagonal ?x)\"\n",
    "\n",
    "            for i in range(self.size_board):\n",
    "                contextRow += f\" (true (cell ?m {i+1} ?x))\"\n",
    "                contextCol += f\" (true (cell {i+1} ?n ?x))\"\n",
    "                contextDia1 += f\" (true (cell 1 {i+1} ?x))\"\n",
    "                contextDia2 += f\" (true (cell 1 {self.size_board-i} ?x))\"\n",
    "\n",
    "            contextRow += \")\\n\"\n",
    "            contextCol += \")\\n\"\n",
    "            contextDia1 += \")\\n\"\n",
    "            contextDia2 += \")\\n\"\n",
    "\n",
    "            context += contextRow + contextCol + contextDia1 + contextDia2 + \"\\n\"\n",
    "            context += \"(<= (line ?x) (row ?m ?x))\\n(<= (line ?x) (column ?m ?x))\\n(<= (line ?x) (diagonal ?x))\\n\\n\"\n",
    "            return context, \"line\"\n",
    "    \n",
    "    def translate_line_byLevel(self):\n",
    "        context = \";\"*80 + \"\\n\" + \";; Win Condition\\n\" + \";\"*80 + \"\\n\"\n",
    "        \n",
    "        for i in range(1, self.length_line):\n",
    "            context += f\"(<= (row ?m ?x) (true (cell ?m {i} ?x)) (true (cell ?m {i+1} ?x)) (true (cell ?m {i+2} ?x)) (true (cell ?m {i+3} ?x)))\\n\"\n",
    "\n",
    "        for i in range(1,self.length_line+1):\n",
    "            context += f\"(<= (column ?n ?x) (true (cell {i} ?n ?x)) (true (cell {i+1} ?n ?x)) (true (cell {i+2} ?n ?x)) (true (cell {i+3} ?n ?x)))\\n\"\n",
    "        \n",
    "        for j in range(1, self.length_line+1):\n",
    "            for i in range(1,self.length_line):\n",
    "                context += f\"(<= (diagonal ?x) (true (cell {j} {i} ?x)) (true (cell {j+1} {i+1} ?x)) (true (cell {j+2} {i+2} ?x)) (true (cell {j+3} {i+3} ?x)))\\n\"\n",
    "        \n",
    "        for j in range(1, self.length_line+1):\n",
    "            for i in range(1,self.length_line):\n",
    "                context += f\"(<= (diagonal ?x) (true (cell {j} {i+3} ?x)) (true (cell {j+1} {i+2} ?x)) (true (cell {j+2} {i+1} ?x)) (true (cell {j+3} {i} ?x)))\\n\"\n",
    "        \n",
    "        context += \"(<= (line ?x) (row ?m ?x))\\n(<= (line ?x) (column ?m ?x))\\n(<= (line ?x) (diagonal ?x))\\n\\n\"\n",
    "        return context, \"line\"\n",
    "    \n",
    "    def translate_reachWin(self):\n",
    "        context = \";\"*80 + \"\\n\" + \";; Win Condition\\n\" + \";\"*80 + \"\\n\"\n",
    "        for i in range(self.num_pl):\n",
    "            context += f\"(<= {GAME_PLAYER[i]}win (index ?x) (true (cellholds ?x {(i-1)%self.size_board+1} {GAME_PLAYER[i]})))\\n\"\n",
    "            context += f\"(<= {GAME_PLAYER[i]}win (not {GAME_PLAYER[(i+1)%self.num_pl]}cell))\\n\"\n",
    "            context += f\"(<= {GAME_PLAYER[i]}cell (cell ?x ?y) (true (cellholds ?x ?y {GAME_PLAYER[i]})))\\n\"\n",
    "        context += \"\\n\"\n",
    "        return context, \"ReachWin\"\n",
    "        \n",
    "class LudiiTerminalKey:\n",
    "    def __init__(self, terminal_key, num_pl):\n",
    "        self.terminal_key = terminal_key\n",
    "        self.num_pl = num_pl\n",
    "        \n",
    "    def translate(self):\n",
    "        if self.terminal_key == \"line\":\n",
    "            context = \";\"*80 + \"\\n\" + \";;; End\\n\" + \";\"*80 + \"\\n\"\n",
    "            for i in range(self.num_pl):\n",
    "                context += f\"(<= terminal(line {CELL_MART[i]}))\\n\"\n",
    "            context += \"(<= terminal(not open))\\n\\n\" # draw\n",
    "        \n",
    "        elif self.terminal_key == \"ReachWin\":\n",
    "            context = \";\"*80 + \"\\n\" + \";;; End\\n\" + \";\"*80 + \"\\n\"\n",
    "            for i in range(self.num_pl):\n",
    "                context += f\"(<= terminal {GAME_PLAYER[i]}win)\\n\"\n",
    "        return context\n",
    "    \n",
    "\n",
    "    \n",
    "class LudiiReward:\n",
    "    def __init__(self, reward_key, num_pl):\n",
    "        self.reward_key = reward_key\n",
    "        self.num_pl = num_pl\n",
    "    \n",
    "    \n",
    "    def translate(self):\n",
    "        context = \";\"*80 + \"\\n\" + \";;; Reward\\n\" + \";\"*80 + \"\\n\"\n",
    "        if self.reward_key == \"line\":\n",
    "            for i in range(len(TERMINAL_CONDITION)):\n",
    "                for j in range(self.num_pl):\n",
    "                    if PLAYERREWARD[TERMINAL_CONDITION[i]] == 100:\n",
    "                        context += f\"(<= (goal {GAME_PLAYER[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) (line {CELL_MART[j]}))\\n\"\n",
    "                    elif PLAYERREWARD[TERMINAL_CONDITION[i]] == 0:\n",
    "                        context += f\"(<= (goal {GAME_PLAYER[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) (line {CELL_MART[j-1]}))\\n\"\n",
    "                    else:\n",
    "                        context += f\"(<= (goal {GAME_PLAYER[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) \"\n",
    "                        for z in range(self.num_pl):\n",
    "                            context += f\"(not (line {CELL_MART[z]})) \"\n",
    "                        context += \"(not open))\\n\"\n",
    "        \n",
    "        elif self.reward_key == \"ReachWin\":\n",
    "            for i in range(len(TERMINAL_CONDITION)):\n",
    "                for j in range(self.num_pl):\n",
    "                    if PLAYERREWARD[TERMINAL_CONDITION[i]] == 100:\n",
    "                        context += f\"(<= (goal {GAME_PLAYER[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) {GAME_PLAYER[j]}win)\\n\"\n",
    "                    elif PLAYERREWARD[TERMINAL_CONDITION[i]] == 0:\n",
    "                        context += f\"(<= (goal {GAME_PLAYER[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) {GAME_PLAYER[(j+1)%self.num_pl]}win)\\n\"\n",
    "\n",
    "        return context\n",
    "    \n",
    "    def translate_draw(self, draw=False):\n",
    "        context = self.translate()\n",
    "        if draw:\n",
    "            context += \"(<= (goal ?w 70) (role ?w) (not (line x)) (not (line o)) open)\\n\"\n",
    "        else:\n",
    "            context += \"\\n\"\n",
    "        return context\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49d4692d",
   "metadata": {},
   "source": [
    "### class Ludii2GDLTranslation\n",
    "- translate the Ludii to GDL and write into file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "151db064",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Ludii2GDLTranslation:\n",
    "    def __init__(self, filename):\n",
    "        self.filename = filename\n",
    "        self.ludii = ReadFile(filename).GameInfo\n",
    "    \n",
    "    def convert2GDL(self):\n",
    "        game_info = Game(self.ludii['name'])\n",
    "        players_info = Players(self.ludii['players'])\n",
    "        equipment_info = Equipment(self.ludii['equipment'])\n",
    "        rules_info = Rules(a.GameInfo['rules'], players_info.num_pl, equipment_info.size_board, equipment_info.type_board)\n",
    "        \n",
    "        self.getGDLFile(game_info.gdl, players_info.gdl, equipment_info.gdl, rules_info.gdl)\n",
    "        print(\"translate completed\")\n",
    "    \n",
    "    def getGDLFile(self, game_gdl, players_gdl, equipment_gdl, rules_gdl):\n",
    "        with open(self.filename.replace(\".lud\", \".gdl\"), 'w+') as fp:\n",
    "            fp.write(game_gdl)\n",
    "            fp.write(players_gdl)\n",
    "            fp.write(equipment_gdl)\n",
    "            fp.write(rules_gdl)\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad8faa9a",
   "metadata": {},
   "source": [
    "# test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "id": "0495dfe8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "translate completed\n"
     ]
    }
   ],
   "source": [
    "Ludii2GDLTranslation('ConnectFour.lud').convert2GDL()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "id": "7ee8e9b0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'name': 'Connect Four', 'players': '2', 'equipment': ['(board (rectangle 1 7))', '(piece \"Disc\" Each)'], 'rules': ['(play (move Add (to (forEach (sites Board) if:(< (size Stack at:(site)) 6))) stack:True))', '(end (if (is Line 4 byLevel:True) (result Mover Win)))']}\n"
     ]
    }
   ],
   "source": [
    "a = ReadFile('ConnectFour.lud')\n",
    "\n",
    "#a = ReadFile('Breakthrough.lud')\n",
    "print(a.GameInfo)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "id": "ef8afc05",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': 'Connect Four',\n",
       " 'players': '2',\n",
       " 'equipment': ['(board (rectangle 1 7))', '(piece \"Disc\" Each)'],\n",
       " 'rules': ['(play (move Add (to (forEach (sites Board) if:(< (size Stack at:(site)) 6))) stack:True))',\n",
       "  '(end (if (is Line 4 byLevel:True) (result Mover Win)))']}"
      ]
     },
     "execution_count": 118,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.GameInfo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "id": "66d8119a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";;; Connect Four\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";; Roles\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(role P1)\n",
      "(role P2)\n",
      "\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";; Game Mode\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(<= (next (control P1)) (true (control P2)))\n",
      "(<= (next (control P2)) (true (control P1)))\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "game_info = Game(a.GameInfo['name'])\n",
    "players_info = Players(a.GameInfo['players'])\n",
    "\n",
    "print(game_info.gdl)\n",
    "print(players_info.gdl)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "id": "80be9d7f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";; Initial State\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(init (cell 1 0 dirt))\n",
      "(init (cell 2 0 dirt))\n",
      "(init (cell 3 0 dirt))\n",
      "(init (cell 4 0 dirt))\n",
      "(init (cell 5 0 dirt))\n",
      "(init (cell 6 0 dirt))\n",
      "(init (cell 7 0 dirt))\n",
      "(init (cell 1 1 b))\n",
      "(init (cell 1 2 b))\n",
      "(init (cell 1 3 b))\n",
      "(init (cell 1 4 b))\n",
      "(init (cell 1 5 b))\n",
      "(init (cell 1 6 b))\n",
      "(init (cell 2 1 b))\n",
      "(init (cell 2 2 b))\n",
      "(init (cell 2 3 b))\n",
      "(init (cell 2 4 b))\n",
      "(init (cell 2 5 b))\n",
      "(init (cell 2 6 b))\n",
      "(init (cell 3 1 b))\n",
      "(init (cell 3 2 b))\n",
      "(init (cell 3 3 b))\n",
      "(init (cell 3 4 b))\n",
      "(init (cell 3 5 b))\n",
      "(init (cell 3 6 b))\n",
      "(init (cell 4 1 b))\n",
      "(init (cell 4 2 b))\n",
      "(init (cell 4 3 b))\n",
      "(init (cell 4 4 b))\n",
      "(init (cell 4 5 b))\n",
      "(init (cell 4 6 b))\n",
      "(init (cell 5 1 b))\n",
      "(init (cell 5 2 b))\n",
      "(init (cell 5 3 b))\n",
      "(init (cell 5 4 b))\n",
      "(init (cell 5 5 b))\n",
      "(init (cell 5 6 b))\n",
      "(init (cell 6 1 b))\n",
      "(init (cell 6 2 b))\n",
      "(init (cell 6 3 b))\n",
      "(init (cell 6 4 b))\n",
      "(init (cell 6 5 b))\n",
      "(init (cell 6 6 b))\n",
      "(init (cell 7 1 b))\n",
      "(init (cell 7 2 b))\n",
      "(init (cell 7 3 b))\n",
      "(init (cell 7 4 b))\n",
      "(init (cell 7 5 b))\n",
      "(init (cell 7 6 b))\n",
      "(index 0) (index 1) (index 2) (index 3) (index 4) (index 5) (index 6) (index 7) (index 8)\n",
      "(++ 0 1) (++ 1 2)  (++ 2 3)  (++ 3 4)  (++ 4 5)  (++ 5 6)  (++ 6 7)  (++ 7 8)\n",
      "(init (control P1))\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "equipment_info = Equipment(a.GameInfo['equipment'])\n",
    "print(equipment_info.gdl)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "id": "df1f60ee",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'rectangle'"
      ]
     },
     "execution_count": 121,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.GameInfo['rules']\n",
    "Players(a.GameInfo['players']).num_pl\n",
    "equipment_info.size_board\n",
    "equipment_info.type_board"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "id": "7aeab7b6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";; Legal Action\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(<= open (true (cell ?m ?n b)))\n",
      "(<= (legal P2 noop) (true (control P1)))\n",
      "(<= (legal P1 noop) (true (control P2)))\n",
      "(<= (legal ?w (drop ?c)) (true (cell ?c ?y2 b)) (filled ?c ?y1) (++ ?y1 ?y2) (true (control ?w)))\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";;  Move & Update\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(<= (next (cell ?c ?h2 x)) (does P1 (drop ?c)) (true (cell ?c ?h2 b)) (filled ?c ?h1) (++ ?h1 ?h2))\n",
      "(<= (next (cell ?c ?h2 o)) (does P2 (drop ?c)) (true (cell ?c ?h2 b)) (filled ?c ?h1) (++ ?h1 ?h2))\n",
      "(<= (next (cell ?c ?y2 b)) (true (cell ?c ?y1 b)) (distinct ?y1 6) (++ ?y1 ?y2))\n",
      "(<= (next (cell ?x ?y ?z)) (true (cell ?x ?y ?z)) (distinct ?z b))\n",
      "(<= (next (cell ?c2 ?y b)) (does ?w (drop ?c1)) (true (cell ?c2 ?y b)) (distinct ?c1 ?c2))\n",
      "(<= (filled ?c ?h) (true (cell ?c ?h x)))\n",
      "(<= (filled ?c ?h) (true (cell ?c ?h o)))\n",
      "(<= (filled ?c ?h) (true (cell ?c ?h dirt)))\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";; Win Condition\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(<= (row ?m ?x) (true (cell ?m 1 ?x)) (true (cell ?m 2 ?x)) (true (cell ?m 3 ?x)) (true (cell ?m 4 ?x)))\n",
      "(<= (row ?m ?x) (true (cell ?m 2 ?x)) (true (cell ?m 3 ?x)) (true (cell ?m 4 ?x)) (true (cell ?m 5 ?x)))\n",
      "(<= (row ?m ?x) (true (cell ?m 3 ?x)) (true (cell ?m 4 ?x)) (true (cell ?m 5 ?x)) (true (cell ?m 6 ?x)))\n",
      "(<= (column ?n ?x) (true (cell 1 ?n ?x)) (true (cell 2 ?n ?x)) (true (cell 3 ?n ?x)) (true (cell 4 ?n ?x)))\n",
      "(<= (column ?n ?x) (true (cell 2 ?n ?x)) (true (cell 3 ?n ?x)) (true (cell 4 ?n ?x)) (true (cell 5 ?n ?x)))\n",
      "(<= (column ?n ?x) (true (cell 3 ?n ?x)) (true (cell 4 ?n ?x)) (true (cell 5 ?n ?x)) (true (cell 6 ?n ?x)))\n",
      "(<= (column ?n ?x) (true (cell 4 ?n ?x)) (true (cell 5 ?n ?x)) (true (cell 6 ?n ?x)) (true (cell 7 ?n ?x)))\n",
      "(<= (diagonal ?x) (true (cell 1 1 ?x)) (true (cell 2 2 ?x)) (true (cell 3 3 ?x)) (true (cell 4 4 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 1 2 ?x)) (true (cell 2 3 ?x)) (true (cell 3 4 ?x)) (true (cell 4 5 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 1 3 ?x)) (true (cell 2 4 ?x)) (true (cell 3 5 ?x)) (true (cell 4 6 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 2 1 ?x)) (true (cell 3 2 ?x)) (true (cell 4 3 ?x)) (true (cell 5 4 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 2 2 ?x)) (true (cell 3 3 ?x)) (true (cell 4 4 ?x)) (true (cell 5 5 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 2 3 ?x)) (true (cell 3 4 ?x)) (true (cell 4 5 ?x)) (true (cell 5 6 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 3 1 ?x)) (true (cell 4 2 ?x)) (true (cell 5 3 ?x)) (true (cell 6 4 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 3 2 ?x)) (true (cell 4 3 ?x)) (true (cell 5 4 ?x)) (true (cell 6 5 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 3 3 ?x)) (true (cell 4 4 ?x)) (true (cell 5 5 ?x)) (true (cell 6 6 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 4 1 ?x)) (true (cell 5 2 ?x)) (true (cell 6 3 ?x)) (true (cell 7 4 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 4 2 ?x)) (true (cell 5 3 ?x)) (true (cell 6 4 ?x)) (true (cell 7 5 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 4 3 ?x)) (true (cell 5 4 ?x)) (true (cell 6 5 ?x)) (true (cell 7 6 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 1 4 ?x)) (true (cell 2 3 ?x)) (true (cell 3 2 ?x)) (true (cell 4 1 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 1 5 ?x)) (true (cell 2 4 ?x)) (true (cell 3 3 ?x)) (true (cell 4 2 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 1 6 ?x)) (true (cell 2 5 ?x)) (true (cell 3 4 ?x)) (true (cell 4 3 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 2 4 ?x)) (true (cell 3 3 ?x)) (true (cell 4 2 ?x)) (true (cell 5 1 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 2 5 ?x)) (true (cell 3 4 ?x)) (true (cell 4 3 ?x)) (true (cell 5 2 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 2 6 ?x)) (true (cell 3 5 ?x)) (true (cell 4 4 ?x)) (true (cell 5 3 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 3 4 ?x)) (true (cell 4 3 ?x)) (true (cell 5 2 ?x)) (true (cell 6 1 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 3 5 ?x)) (true (cell 4 4 ?x)) (true (cell 5 3 ?x)) (true (cell 6 2 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 3 6 ?x)) (true (cell 4 5 ?x)) (true (cell 5 4 ?x)) (true (cell 6 3 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 4 4 ?x)) (true (cell 5 3 ?x)) (true (cell 6 2 ?x)) (true (cell 7 1 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 4 5 ?x)) (true (cell 5 4 ?x)) (true (cell 6 3 ?x)) (true (cell 7 2 ?x)))\n",
      "(<= (diagonal ?x) (true (cell 4 6 ?x)) (true (cell 5 5 ?x)) (true (cell 6 4 ?x)) (true (cell 7 3 ?x)))\n",
      "(<= (line ?x) (row ?m ?x))\n",
      "(<= (line ?x) (column ?m ?x))\n",
      "(<= (line ?x) (diagonal ?x))\n",
      "\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";;; Reward\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(<= (goal P1 100) (line x))\n",
      "(<= (goal P2 100) (line o))\n",
      "(<= (goal P1 50) (not (line x)) (not (line o)) (not open))\n",
      "(<= (goal P2 50) (not (line x)) (not (line o)) (not open))\n",
      "(<= (goal P1 0) (line o))\n",
      "(<= (goal P2 0) (line x))\n",
      "(<= (goal ?w 70) (role ?w) (not (line x)) (not (line o)) open)\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";;; End\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "(<= terminal(line x))\n",
      "(<= terminal(line o))\n",
      "(<= terminal(not open))\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#ru = Rules(a.GameInfo['rules'], Players(a.GameInfo['players']).num_pl, 3, \"square\")\n",
    "ru = Rules(a.GameInfo['rules'], Players(a.GameInfo['players']).num_pl, equipment_info.size_board, equipment_info.type_board)\n",
    "print(ru.gdl)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "73fec623",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      ";;; Reward\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(ru.gdl)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "97f6b52f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['(', 'game \"Breakthrough\" ', '(', 'players {', '(', 'player N', ')', ' ', '(', 'player S', ')', '}', ')', ' ', '(', 'equipment', ' (board (Square 8)) (piece \"Pawn\" Each (or { \"StepForwardToEmpty\" (move Step (directions {FR FL}) (to if:(or (is Empty (to)) (\"IsEnemyAt\" (to)) ) (apply (remove (to))) ) ) }) ) (regions P1 (sites Top)) (regions P2 (sites Bottom)) ', ' ', '(', 'rules ', '(', 'start { ', '(', 'place \"Pawn1\" ', '(', 'expand ', '(', 'sites Bottom', ')', '', ')', '', ')', ' ', '(', 'place \"Pawn2\" ', '(', 'expand ', '(', 'sites Top', ')', '', ')', '', ')', ' }', ')', '  ', '(', 'play ', '(', 'forEach Piece', ')', '', ')', '  ', '(', 'end ', '(', '\"ReachWin\" ', '(', 'sites Mover', ')', ' Mover', ')', '', ')', ' ', ')', ' ', ')']\n",
      "================================================================================\n",
      "{'name': 'Breakthrough', 'players': '(player N) (player S)', 'equipment': ['(board (Square 8))', '(piece \"Pawn\" Each (or { \"StepForwardToEmpty\" (move Step (directions {FR FL}) (to if:(or (is Empty (to)) (\"IsEnemyAt\" (to)) ) (apply (remove (to))) ) ) }) )', '(regions P1 (sites Top))', '(regions P2 (sites Bottom))'], 'rules': ['(start { (place \"Pawn1\" (expand (sites Bottom))) (place \"Pawn2\" (expand (sites Top))) })', '(play (forEach Piece))', '(end (\"ReachWin\" (sites Mover) Mover))']}\n"
     ]
    }
   ],
   "source": [
    "a = ReadFile_test('Breakthrough.lud')\n",
    "print(\"=\"*80)\n",
    "print(a.GameInfo)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "ae7bae8b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['(', 'game \"Connect Four\" ', '(', 'players 2', ')', ' ', '(', 'equipment', ' (board (rectangle 1 7)) (piece \"Disc\" Each) ', '  ', '(', 'rules ', '(', 'play ', '(', 'move Add ', '(', 'to ', '(', 'forEach ', '(', 'sites Board', ')', ' if:', '(', '< ', '(', 'size Stack at:', '(', 'site', ')', '', ')', ' 6', ')', '', ')', '', ')', ' stack:True', ')', '', ')', ' ', '(', 'end ', '(', 'if ', '(', 'is Line 4 byLevel:True', ')', ' ', '(', 'result Mover Win', ')', '', ')', '', ')', ' ', ')', ' ', ')']\n",
      "================================================================================\n",
      "{'name': 'Connect Four', 'players': '2', 'equipment': ['(board (rectangle 1 7))', '(piece \"Disc\" Each)'], 'rules': ['(play (move Add (to (forEach (sites Board) if:(< (size Stack at:(site)) 6))) stack:True))', '(end (if (is Line 4 byLevel:True) (result Mover Win)))']}\n"
     ]
    }
   ],
   "source": [
    "a = ReadFile_test('ConnectFour.lud')\n",
    "print(a.GameInfo)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
